import { _decorator, Component, Node, instantiate, Vec2, Vec3, Asset, UITransform, misc, Prefab } from 'cc';
import { MapCtrl } from '../Ctrl/MapCtrl';
import AssetsMgr from '../Model/AssetsMgr';
import GameEventMgr, { GameEvent } from '../Model/GameEventMgr';
import { ISpawnerEventCall, SpawnEvent, SpawnerCom } from './Component/SpawnerCom';
import { Unit } from './Unit';
import { FactoryCom } from './Component/FactoryCom';
import { Tools } from '../Util/Tools';
import { Global, LootType, UnitType } from '../Util/Global';
import { UICtrl } from '../Ctrl/UICtrl';
import { EconomicCom } from './Component/EconomicCom';
import { Loot } from './Loot';
import { LocalStorageCtrl, StorageKey } from '../Ctrl/LocalStorageCtrl';
import PoolManager from '../Ctrl/PoolManager';
import { DestructableCom } from './Component/DestructableCom';
const { ccclass, property } = _decorator;

@ccclass('MapSpawner')
export class MapSpawner extends SpawnerCom {
    //孵化区域的节点(整个地图背景四个区块中的一个)
    spawnBaseNode: Node = null;
    mapCtrl: MapCtrl = null;
    maxUnitPlanetCount: number = 50;
    spawnUnitWeightMap: Map<UnitType, number> = new Map();
    totalWeight: number = 100;

    enableSpawn: boolean = false;

    private _spawnCD: number = 0;

    start() {
        // let tutorialFinish = LocalStorageCtrl.getBooleanValue(StorageKey.FPTutorialFinish);
        // if (tutorialFinish) {
        //     this.enableSpawn = tutorialFinish;
        // }
        GameEventMgr.Register(this, GameEvent.UnitInitComplete, this.spawnUnitFinishHandler.bind(this));
        GameEventMgr.Register(this, GameEvent.UpdateLocalStorageValue, (key, value) => {
            if (key == StorageKey.FPTutorialFinish) {
                this.enableSpawn = value && Global.EnableMapSpawn;
            }
        });

        if (Global.config) {
            for (let i = 0; i < Global.config['levelCfg'].length; i++) {
                let spawnerCfg = Global.config['levelCfg'][i].map_unlocked;
                let spawnerMap = Object.keys(spawnerCfg);
                if (spawnerMap && spawnerMap.length > 0) {
                    spawnerMap.forEach((prop: string) => {
                        if (i == 0) {
                            this.spawnUnitWeightMap.set(UnitType[prop], spawnerCfg[prop]);
                            this.livePlanetProbability = Global.config['levelCfg'][0].livePlanetProbability;
                        }
                        let unit_arr = AssetsMgr.unitPrefabMap.get(UnitType[prop]);
                        unit_arr.forEach((v: Prefab, k: string) => {
                            this.AddProduct(v);
                        })
                    })
                }
            }
        }
        this.AddProduct(AssetsMgr.getUnitPrefab(UnitType.Loot));

        this.totalWeight = 0;
        this.spawnUnitWeightMap.forEach(v => {
            this.totalWeight += v;
        })

        // this.RandomSpawnUnitCD();
    }

    livePlanetProbability: number = 0.5;
    ChangeSpawnWeight(level: number) {

        if (Global.config && Global.config['levelCfg'][level - 1]) {
            let spawnerCfg = Global.config['levelCfg'][level - 1].map_unlocked;
            let spawnerMap = Object.keys(spawnerCfg);
            if (spawnerMap && spawnerMap.length > 0) {
                this.spawnUnitWeightMap.clear();
                spawnerMap.forEach((prop: string) => {
                    this.spawnUnitWeightMap.set(UnitType[prop], spawnerCfg[prop]);
                })
            }
            try {
                this.livePlanetProbability = Global.config['levelCfg'][level - 1].livePlanetProbability;
                if (this.livePlanetProbability <= 0) {
                    this.livePlanetProbability = 0.5;
                }
            } catch (error) {
                console.error('配置出错!');
                this.livePlanetProbability = 0.5;
            }
        }

        this.totalWeight = 0;
        this.spawnUnitWeightMap.forEach(v => {
            this.totalWeight += v;
        })
    }

    Spawning(dt) {
        if (this._spawnCD > 0) {
            this._spawnCD -= dt;
        }

        if (this.spawnUnit && this._spawningCount > 0) {// && this.spawnBaseNode) {
            let remainNum = 0;
            for (let i = 0; i < this.workshop.length; i++) {
                //生产位置
                let has = this.workshop[i].Producing(dt);
                if (has) {
                    let worldPos = this.RandomAnglePos(30);
                    Tools.IsPositionInTransform(worldPos, UICtrl.Instance.viewGraphicsTran, worldPos)

                    // let node = instantiate(this.spawnPrefabs.get(this.workshop[i].productType));
                    // let p = this.spawnPrefabs.get(this.workshop[i].productType);
                    let p = this.workshop[i].prefeb;
                    let node = PoolManager.getNode(p);
                    // node.active = false;
                    node.setWorldPosition(worldPos);

                    node.setParent(this.childrenParent || this.node.parent);
                    let unit = node.getComponent(Unit);
                    // unit.prefabName = p.name;
                    unit.parentUnit = this.unit;

                    this.spawnUnit.push(unit);

                    this._onSpawnEventCall.forEach((pool, key) => {
                        for (let i = 0; i < pool.length; i++) {
                            let call = pool[i];
                            if (!call.SpawnEventCallback(unit, SpawnEvent.SPAWNING)) {
                                break;
                            }
                        }
                    });

                    let ran = Math.random();
                    if (unit.unitType == UnitType.UnitPlanet) {
                        let fa = unit.node.getComponent(FactoryCom);
                        let ec = unit.node.getComponent(EconomicCom);
                        if (fa) {
                            fa.destroy();
                        }
                        if (ec) {
                            ec.destroy();
                        }
                        //设定生命星球 挂载工厂组件
                        if (ran < this.livePlanetProbability) {
                            fa = unit.node.addComponent(FactoryCom);
                            ec = unit.node.addComponent(EconomicCom);

                            ec.mine_res = 200 * Global.gameManager.playerData.difficulty;
                        }
                    }

                    // this.spawnUnitFinishHandler(unit);
                }
                remainNum += this.workshop[i].productNum;
            }

            this._spawningCount = remainNum;
        }

    }

    /**随机区块的一个位置
     * @return 世界坐标
     */
    RandomPos(): Vec3 {
        let transform = this.node.getComponent(UITransform)
        let size = transform.contentSize;
        let posX = Math.random() * (size.x) - size.x / 2;
        let posY = Math.random() * (size.y) - size.y / 2;
        let result = new Vec3(posX, posY, 0);
        let worldPos = transform.convertToWorldSpaceAR(result);
        // let worldPos = new Vec3(880,480,0)
        return worldPos;
    }

    /**
     * 随机返回一个以玩家为中心，给定角度的扇形区域内的随机位置
     * @param angle 扇形的角度，单位为度
     * @return 世界坐标
     */
    RandomAnglePos(angle: number): Vec3 {
        let transform = this.node.getComponent(UITransform);
        let size = transform.contentSize;  // contentSize 决定半径
        let radius = size.width / 2;       // 假设 width 为直径，半径为 width / 2

        if (this.mapCtrl && this.mapCtrl.player && !this.mapCtrl.player.death) {

        }
        else {
            return this.RandomPos();
        }

        let playerPos = this.mapCtrl.player.node.position.clone();
        let playerV = this.mapCtrl.player.rigBody.linearVelocity.normalize();

        // 获取 linearVelocity 的角度
        let baseAngle = Math.atan2(playerV.y, playerV.x) * (180 / Math.PI);

        // 在给定的扇形角度范围内生成一个随机角度
        let randomAngle = baseAngle + (Math.random() - 0.5) * angle;

        // 将随机角度转换为弧度
        let radian = randomAngle * (Math.PI / 180);

        // 生成随机半径，点落在半径范围内
        let randomRadius = Math.random() * radius;

        // 计算在扇形区域内的随机点
        let posX = randomRadius * Math.cos(radian);
        let posY = randomRadius * Math.sin(radian);
        let result = new Vec3(posX, posY, 0);

        // 将该点从局部坐标系转换为世界坐标系
        let worldPos = playerPos.add(result);
        worldPos = Global.GameNodeTran.convertToWorldSpaceAR(worldPos);

        return worldPos;
    }

    //随机孵化地图单位 游戏开始
    RandomSpawnUnitCD(finishCD: number = 0) {
        if (!this.mapCtrl) {
            return;
        }
        if (this._spawnCD > 0) {
            return;
        }

        this._spawnCD = finishCD;

        this.RandomSpawnUnitImmediately();
    }

    RandomSpawnUnitImmediately() {
        if (!this.enableSpawn) {
            return
        }
        let deR = this.mapCtrl.unitCountInMap / this.maxUnitPlanetCount;
        let baseR = 1 - deR;

        let ran = Math.random();
        if (baseR > 0 && ran < baseR) {
            let subR = ran / baseR;
            let unitType = this.checkUnitTypeByWeight(subR * this.totalWeight);

            //可选预制体
            let unit_arr = this.spawnPrefabs.get(unitType);
            if (unit_arr.size > 1) {
                // let ran_2 = Tools.getRandomInt(0, unit_arr.size - 1);

                let prefab = Tools.weightedRandomSelect(Array.from(unit_arr.values()), false);
                this.AddProductNum(prefab, 1);
            }
            else {
                this.AddProductNum(unitType, 1);//控制地图孵化
            }

        }
    }

    /**立即生产数个掉落物 */
    SpawnUnitImmediatelyLoot(lootId: LootType, pos: Vec3, num = 1, content = 0) {

        let work = this.getWorkshop(UnitType.Loot);
        if (!work) {
            return;
        }
        work.AddProductNum(num);

        let self = this;
        let call: ISpawnerEventCall = {
            SpawnEventCallback(unit: Unit, event: SpawnEvent) { //闭包
                if (unit && unit.unitType == UnitType.Loot && event == SpawnEvent.SPAWNING) {
                    let loot = unit.getComponent(Loot) || unit.addComponent(Loot);
                    loot.loot_id = lootId;
                    loot.content = content;
                    unit.node.setWorldPosition(pos);

                    num--;
                    if (num <= 0) {
                        self.offSpawnEventCallback('MapSpawnerLootHandle', this);
                    }
                    return false;
                }
                return true;
            },
        }

        //同时只能存在一个事件，多次注册会覆盖，使用不同uniqueKey
        this.onSpawnEventCallback('MapSpawnerLootHandle', call);
    }

    /**立即生产数个单位 */
    SpawnUnitImmediately(prefab: Prefab, pos: Vec3, num = 1, finish?: (node: Node, index: number) => void) {

        let work = this.getWorkshop(prefab);
        if (!work) {
            if (!prefab.data.getComponent(Unit)) {
                //只能孵化单位预制体
                return;
            }
            this.AddProduct(prefab);
            work = this.getWorkshop(prefab);
        }
        work.AddProductNum(num);

        let self = this;
        let start_count = num;
        let call: ISpawnerEventCall = {
            SpawnEventCallback(unit: Unit, event: SpawnEvent) { //闭包
                if (unit && unit.prefabName == prefab.name && event == SpawnEvent.SPAWNING) {
                    unit.node.setWorldPosition(pos);

                    finish && finish(unit.node, start_count - num);
                    num--;
                    if (num <= 0) {
                        self.offSpawnEventCallback('MapSpawnerUnitImmediately', this);
                    }
                    return false;
                }
                return true;
            },
        }

        //同时只能存在一个事件，多次注册会覆盖，使用不同uniqueKey
        this.onSpawnEventCallback('MapSpawnerUnitImmediately', call);
    }

    SpwanPrefabImmediate(wpos: Vec2 | Vec3, prefab: Prefab): Node {
        if (!prefab) {
            return;
        }

        let node = PoolManager.getNode(prefab);

        //如果孵化的对象包含碰撞体 且正是因为碰撞事件而立即孵化的 会出现报错 要么延后一帧
        node.setParent(Global.GameNode);
        node.setWorldPosition(wpos.x, wpos.y, 0);

        return node;
    }

    /**根据权重计算出单位类型 */
    checkUnitTypeByWeight(weight: number): UnitType {
        let sum = 0;
        let target: UnitType = UnitType.Base;
        for (let kv of this.spawnUnitWeightMap) {
            sum += kv[1];
            target = kv[0];
            if (sum > weight) {
                break;
            }
        }
        return target;
    }

    protected spawnUnitFinishHandler(unit: Unit) {
        if (this.spawnUnit.includes(unit) && !unit.parentUnit) {
            //随机给以一个初速度
            let angle = misc.degreesToRadians(Math.random() * 360);
            // 使用三角函数计算坐标
            let x = Math.cos(angle);
            let y = Math.sin(angle);

            let pos = new Vec3(x, y, 0);
            unit.GetRotatedPos(pos);
            pos.multiplyScalar(unit.moveAcceleration);
            unit.rigBody.linearVelocity = unit.rigBody.linearVelocity.add(unit.ToVec2(pos));
        }

        if (unit.unitType > UnitType.UnitSpacecra) {
            // if (Tools.IsPositionInTransform(unit.unitWorldPos, UICtrl.Instance.uiGraphicsTran)) {
            //     GameEventMgr.Dispatch(GameEvent.LogGameMessage, "孵化异常==>在视野内！")
            // }
            if (!Tools.IsPositionInTransform(unit.unitWorldPos, this.mapCtrl.getComponent(UITransform))) {
                // GameEventMgr.Dispatch(GameEvent.LogGameMessage, "孵化异常==>在地图外！")
                unit.deathTime = 5;
            }
        }
    }
}


